package zeroj.orm.ibatis;

import java.io.IOException;
import java.io.Reader;
import java.sql.SQLException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import zeroj.orm.DaoException;

import com.ibatis.common.resources.Resources;
import com.ibatis.sqlmap.client.SqlMapClient;
import com.ibatis.sqlmap.client.SqlMapClientBuilder;
import com.ibatis.sqlmap.client.SqlMapSession;

/**
 * 
 * @author lyl
 * 
 * @since 1.0
 * 
 * 2008-9-12
 */
public class IbatisSupport {

	private static final Log log = LogFactory.getLog(IbatisSupport.class);
	
	private static IbatisSupport instance = new IbatisSupport();
	private ThreadLocal<IbatisSession> session = new ThreadLocal<IbatisSession>();
	private SqlMapClient sqlMapClient;
	
	private IbatisSupport() {
		initClient();
	}
	public static SqlMapSession currentSession(boolean create) {
		
		IbatisSession session = instance.session.get();
		if(session == null && create) {
			log.debug("open new session");
			session = new IbatisSession(instance.sqlMapClient.openSession());
			instance.session.set(session);
		}
		return session == null ? null : session.session;
	}
	public static SqlMapSession existSession() {
		
		return currentSession(false);
	}
	public static SqlMapSession currentSession() {
		
		return currentSession(true);
	}
	public static void closeSession() {
		
		IbatisSession session = instance.session.get();
		if(session != null) {
			log.debug("close session");
			try {
				if(session.inTransaction)
					session.session.endTransaction();
			} catch (SQLException e) {
				//no process needed
				log.warn("Cannot end transaction", e);
			}
			session.session.close();
			instance.session.remove();
		}
	}
	public static void commit() {
		
		IbatisSession session = instance.session.get();
		if(session != null)
			try {
				if(session.inTransaction)
					session.session.commitTransaction();
			} catch (SQLException e) {
				//no process needed
				log.warn("commit failed", e);
			}
	}
	public static void startTransaction() throws DaoException {
		
		try {
			currentSession().startTransaction();
		} catch (SQLException sqle) {
			log.warn("Cannot start transaction", sqle);
			throw new DaoException(sqle);
		}
		instance.session.get().inTransaction = true;
	}
	private void initClient() {
		
		log.debug("init client");
		try {
			Reader reader = Resources.getResourceAsReader("SqlMapConfig.xml");
			sqlMapClient = SqlMapClientBuilder.buildSqlMapClient(reader);
			reader.close();
		} catch (IOException e) {
			log.fatal("init ibatis client fialed", e);
			throw new RuntimeException("init ibatis client failed", e);
		}		
	}
	
	private static class IbatisSession {
		
		SqlMapSession session;
		boolean inTransaction = false;
		
		IbatisSession(SqlMapSession session) {
			this.session = session;
		}
	}
}
